package org.seedltd.upms.service.impl.detection;

import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.seedltd.core.utils.BeanUtils;
import org.seedltd.core.utils.DateUtils;
import org.seedltd.core.utils.JsonUtils;
import org.seedltd.pay.weChar.WeCharPayService;
import org.seedltd.upms.model.detection.dto.PayOrderDTO;
import org.seedltd.upms.model.detection.dto.RefundOrderDTO;
import org.seedltd.upms.model.detection.vo.JsapiResultVO;
import org.seedltd.upms.model.detection.vo.QueryVO;
import org.seedltd.upms.model.detection.vo.RefundVO;
import org.seedltd.upms.service.detection.DetectionWeCharPayService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;

import cn.hutool.core.date.DateUtil;

/**
 * 实现
 *
 * @author laizuan
 * @version 1.0
 * @since 2021/8/12 14:41
 */
@Service
public class DetectionWeCharPayServiceImpl implements DetectionWeCharPayService {
    private final WeCharPayService weCharPayService;

    @Value("${spring.profiles.active}")
    private String dev;

    @Value("${seedltd.wx.notify-base-url}")
    private String notifyBaseUrl;

    @Value("${seedltd.wx.refund-notify}")
    private String refundNotify;

    @Value("${seedltd.wx.pay-notify}")
    private String payNotify;

    public DetectionWeCharPayServiceImpl(WeCharPayService weCharPayService) {
        this.weCharPayService = weCharPayService;
    }

    private boolean isDev() {
        return "dev".equals(dev);
    }

    private String getNotifyUrl(boolean isPay) {
        if (isPay) {
            return notifyBaseUrl + payNotify;
        }
        return notifyBaseUrl + refundNotify;
    }

    @Override
    public QueryVO query(String outTradeNo) throws Exception {
        WxPayOrderQueryV3Request wxPayOrderQueryV3Request = new WxPayOrderQueryV3Request();
        wxPayOrderQueryV3Request.setOutTradeNo(outTradeNo);
        WxPayOrderQueryV3Result wxPayOrderQueryV3Result = this.weCharPayService.queryOrderV3(wxPayOrderQueryV3Request);
        String status = wxPayOrderQueryV3Result.getTradeState();

        QueryVO queryVO = new QueryVO();
        queryVO.setSuccess(false);
        queryVO.setBody(JsonUtils.toJsonString(wxPayOrderQueryV3Result));
        if (StringUtils.equalsIgnoreCase(status, "SUCCESS")) {
            queryVO.setSuccess(true);
        }
        return queryVO;
    }

    @Override
    public boolean closeOrder(String outTradeNo) throws WxPayException {
        weCharPayService.closeOrderV3(outTradeNo);
        return true;
    }

    @Override
    @Transactional
    public RefundVO refund(RefundOrderDTO refundOrder) throws Exception {

        WxPayRefundV3Request wxPayRefundV3Request = new WxPayRefundV3Request();
        wxPayRefundV3Request.setOutTradeNo(refundOrder.getOutTradeNo());
        wxPayRefundV3Request.setOutRefundNo(refundOrder.getOutRefundNo());
        wxPayRefundV3Request.setReason(refundOrder.getReason());
        wxPayRefundV3Request.setNotifyUrl(getNotifyUrl(false));

        WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
        if (isDev()) {
            amount.setTotal(1);
        } else {
            amount.setTotal(BaseWxPayRequest.yuanToFen(refundOrder.getTotal().toString()));
        }
        amount.setRefund(BaseWxPayRequest.yuanToFen(refundOrder.getRefund().toString()));
        amount.setCurrency("CNY");
        wxPayRefundV3Request.setAmount(amount);
        WxPayRefundV3Result wxPayRefundV3Result = this.weCharPayService.refundV3(wxPayRefundV3Request);

        RefundVO refundVO = new RefundVO();
        BeanUtils.copyProperties(wxPayRefundV3Result, refundVO);
        return refundVO;
    }


    @Override
    public JsapiResultVO createOrder(PayOrderDTO payOrder) throws WxPayException {
        WxPayUnifiedOrderV3Request wxPayUnifiedOrderV3Request = new WxPayUnifiedOrderV3Request();

        wxPayUnifiedOrderV3Request.setDescription(payOrder.getDescription());
        wxPayUnifiedOrderV3Request.setOutTradeNo(payOrder.getOutTradeNo());
        wxPayUnifiedOrderV3Request.setAttach(payOrder.getAttach());
        wxPayUnifiedOrderV3Request.setNotifyUrl(getNotifyUrl(true));

        if (payOrder.getTimeExpire() == null) {
            wxPayUnifiedOrderV3Request
                .setTimeExpire(DateUtil.format(DateUtils.addMinutes(new Date(), 30), "yyyy-MM-dd'T'HH:mm:ss+'08:00'"));
        } else {
            wxPayUnifiedOrderV3Request
                .setTimeExpire(DateUtil.format(payOrder.getTimeExpire(), "yyyy-MM-dd'T'HH:mm:ss+'08:00'"));
        }

        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();

        if (isDev()) {
            amount.setTotal(1);
        } else {
            amount.setTotal(BaseWxPayRequest.yuanToFen(payOrder.getAmount().toString()));
        }
        wxPayUnifiedOrderV3Request.setAmount(amount);

        WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
        payer.setOpenid(payOrder.getOpenid());

        wxPayUnifiedOrderV3Request.setPayer(payer);

        WxPayUnifiedOrderV3Request.SceneInfo sceneInfo = new WxPayUnifiedOrderV3Request.SceneInfo();
        sceneInfo.setPayerClientIp(payOrder.getClientIp());
        wxPayUnifiedOrderV3Request.setSceneInfo(sceneInfo);
        WxPayUnifiedOrderV3Result.JsapiResult jsapiResult =
            weCharPayService.createOrderV3(TradeTypeEnum.JSAPI, wxPayUnifiedOrderV3Request);
        JsapiResultVO jsapiResultVO = new JsapiResultVO();
        BeanUtils.copyProperties(jsapiResult, jsapiResultVO);
        return jsapiResultVO;
    }

}
